from typing import Dict, Any, Tuple, List
import codecs
from protocol.types import DataType
from protocol.common import _err, _ensure_int, _evaluate_simple_condition


def _read_uint(buf: bytes, offset: int, size: int) -> Tuple[int, int]:
    end = offset + size
    if end > len(buf):
        raise _err([], '读取越界')
    return int.from_bytes(buf[offset:end], 'big'), end


def _read_len_by_prefix(prefix: str, buf: bytes, offset: int) -> Tuple[int, int]:
    p = prefix.upper()
    if p == 'BYTE':
        return _read_uint(buf, offset, 1)
    if p == 'WORD':
        return _read_uint(buf, offset, 2)
    if p == 'DWORD':
        return _read_uint(buf, offset, 4)
    raise _err([], f'未知长度前缀: {prefix}')


def _decode_bcd_bytes(buf: bytes, offset: int, num_bytes: int) -> Tuple[str, int]:
    end = offset + num_bytes
    if end > len(buf):
        raise _err([], 'BCD 读取越界')
    out_chars: List[str] = []
    for b in buf[offset:end]:
        out_chars.append(str((b >> 4) & 0x0F))
        out_chars.append(str(b & 0x0F))
    result = ''.join(out_chars)
    # 移除前面的0，但保留至少一个字符
    result = result.lstrip('0') or '0'
    return result, end




def _decode_string(buf: bytes, offset: int, cfg: Dict[str, Any]) -> Tuple[str, int]:
    charset = cfg.get('charset', 'gbk')
    fixed_len = cfg.get('fixedLen')
    len_prefix = cfg.get('lenPrefix')
    remainder = cfg.get('remainder', False)  # 是否解析剩余字节，默认为false
    
    if fixed_len is not None:
        end = offset + int(fixed_len)
        raw = buf[offset:end]
        try:
            # 去除末尾的 0x00
            raw = raw.rstrip(b"\x00")
            return raw.decode(charset, errors='ignore'), end
        except Exception as e:
            raise _err([], f'STRING 解码失败: {e}')
    if len_prefix is not None:
        ln, o1 = _read_len_by_prefix(str(len_prefix), buf, offset)
        end = o1 + ln
        raw = buf[o1:end]
        try:
            return raw.decode(charset, errors='ignore'), end
        except Exception as e:
            raise _err([], f'STRING 解码失败: {e}')
    if remainder:
        # 剩余字节模式：解析从当前位置到缓冲区末尾的所有字节
        raw = buf[offset:]
        try:
            # 去除末尾的 0x00
            raw = raw.rstrip(b"\x00")
            return raw.decode(charset, errors='ignore'), len(buf)
        except Exception as e:
            raise _err([], f'STRING 解码失败: {e}')
    raise _err([], 'STRING 需要 fixedLen、lenPrefix 或 remainder')


def decode_field(buf: bytes, offset: int, field_cfg: Dict[str, Any], path: List[str]) -> Tuple[Any, int]:
    t = str(field_cfg.get('type', '')).upper()
    if t == DataType.BYTE.value:
        return _read_uint(buf, offset, 1)
    if t == DataType.WORD.value:
        return _read_uint(buf, offset, 2)
    if t == DataType.DWORD.value:
        return _read_uint(buf, offset, 4)
    if t == DataType.BCD.value:
        # 约定 digits 为字节数
        bcd_bytes = int(field_cfg.get('digits', 0))
        if bcd_bytes <= 0:
            raise _err(path, 'BCD 需要 digits(字节数)')
        return _decode_bcd_bytes(buf, offset, bcd_bytes)
    if t == DataType.BYTES.value:
        # 优先使用 fixedLen；其次使用 lenPrefix；然后使用 remainder；最后默认读取到当前切片末尾
        fixed_len = int(field_cfg.get('fixedLen', 0))
        len_prefix = field_cfg.get('lenPrefix')
        remainder = field_cfg.get('remainder', False)  # 是否解析剩余字节，默认为false
        ascii_mode = field_cfg.get('ascii', False)  # 默认按HEX解析
        padding_byte = _ensure_int(field_cfg.get('padding', 0x00), path)  # 填充字节，默认0x00，确保是整数
        
        if fixed_len > 0:
            end = offset + fixed_len
            if end > len(buf):
                raise _err(path, 'BYTES 读取越界')
            data_bytes = buf[offset:end]
            offset = end  # 更新offset
        elif len_prefix is not None:
            # 使用长度前缀
            if isinstance(len_prefix, int):
                # 直接指定长度前缀的字节数
                prefix_bytes = len_prefix
                if prefix_bytes == 1:
                    ln, o1 = _read_len_by_prefix('BYTE', buf, offset)
                elif prefix_bytes == 2:
                    ln, o1 = _read_len_by_prefix('WORD', buf, offset)
                elif prefix_bytes == 4:
                    ln, o1 = _read_len_by_prefix('DWORD', buf, offset)
                elif prefix_bytes == 8:
                    # 8字节长度前缀
                    ln, o1 = _read_uint(buf, offset, 8)
                else:
                    raise _err(path, f'不支持的lenPrefix字节数: {prefix_bytes}')
            else:
                # 字符串格式的长度前缀
                ln, o1 = _read_len_by_prefix(str(len_prefix), buf, offset)
            
            end = o1 + ln
            if end > len(buf):
                raise _err(path, 'BYTES 长度前缀超出缓冲区')
            data_bytes = buf[o1:end]
            offset = end  # 更新offset
        elif remainder:
            # 剩余字节模式：解析从当前位置到缓冲区末尾的所有字节
            data_bytes = buf[offset:]
            offset = len(buf)  # 更新offset
        else:
            # 无 fixedLen、lenPrefix 和 remainder，则消费剩余全部（保持向后兼容）
            data_bytes = buf[offset:]
            offset = len(buf)  # 更新offset
        
        if ascii_mode:
            # ASCII模式：右对齐解析，去除前面的填充字节
            if fixed_len > 0:
                # 找到第一个非填充字节的位置
                start_idx = 0
                for i, b in enumerate(data_bytes):
                    if b != padding_byte:
                        start_idx = i
                        break
                # 如果全是填充字节，返回空字符串
                if start_idx == 0 and data_bytes[0] == padding_byte:
                    return "", offset
                # 提取有效数据
                data_bytes = data_bytes[start_idx:]
            
            # 解码为字符串
            try:
                return data_bytes.decode('ascii'), offset
            except UnicodeDecodeError:
                # 如果ASCII解码失败，回退到HEX显示
                return data_bytes.hex(), offset
        else:
            # HEX模式：返回十六进制字符串
            return data_bytes.hex(), offset
    if t == DataType.STRING.value:
        return _decode_string(buf, offset, field_cfg)
    if t == DataType.BITFIELD.value:
        size = int(field_cfg.get('size', 32))
        if size not in [8, 16, 32, 64]:
            raise _err(path, f'BITFIELD size 必须是 8/16/32/64，实际: {size}')
        byte_size = size // 8
        v, o1 = _read_uint(buf, offset, byte_size)
        # 简化BITFIELD解析，只返回简单的bit格式
        bits = field_cfg.get('bits', [])
        if bits:
            result = {}
            for bit_def in bits:
                bit_idx = int(bit_def.get('bitIndex', 0))
                bit_length = int(bit_def.get('bitLength', 1))  # 默认长度为1
                max_idx = size - 1
                
                if 0 <= bit_idx <= max_idx and bit_idx + bit_length - 1 <= max_idx:
                    # 提取连续bit的值（大端序）
                    mask = (1 << bit_length) - 1
                    bit_value = (v >> bit_idx) & mask
                    
                    # 生成简单的字段名
                    if bit_length == 1:
                        field_name = f'bit_{bit_idx}'
                    else:
                        field_name = f'bit_{bit_idx}_{bit_idx + bit_length - 1}'
                    
                    result[field_name] = bit_value
            return result, o1
        return v, o1
    if t == DataType.STRUCT.value:
        fields = field_cfg.get('fields', [])
        if not isinstance(fields, list):
            raise _err(path, 'STRUCT 需要 fields 数组')
        if not fields:
            # 空消息体，返回空字典
            return {}, offset
        # 排序
        fields_sorted = sorted(fields, key=lambda f: int(f['order']))
        out: Dict[str, Any] = {}
        cur = offset
        # 用于条件字段求值的简化上下文（仅BYTE类型写入）
        context: Dict[str, Any] = {}
        for f in fields_sorted:
            name = f.get('name') or ''
            if 'conditional' in f:
                cond = str(f['conditional'])
                # 使用更强大的条件表达式解析
                if ' || ' in cond:
                    # 逻辑或：任一条件满足即可
                    conditions = cond.split(' || ')
                    ok = False
                    for sub_cond in conditions:
                        if _evaluate_simple_condition(sub_cond.strip(), context):
                            ok = True
                            break
                    if not ok:
                        continue
                elif ' && ' in cond:
                    # 逻辑与：所有条件都必须满足
                    conditions = cond.split(' && ')
                    ok = True
                    for sub_cond in conditions:
                        if not _evaluate_simple_condition(sub_cond.strip(), context):
                            ok = False
                            break
                    if not ok:
                        continue
                else:
                    # 简单条件
                    if not _evaluate_simple_condition(cond, context):
                        continue
            val, cur = decode_field(buf, cur, f, path + [name])
            out[name] = val
            if f.get('type') == 'BYTE':
                context[name] = val
        return out, cur
    if t == DataType.ARRAY.value:
        len_prefix = field_cfg.get('lenPrefix')
        count_by_field = field_cfg.get('countByField')
        
        if not len_prefix:
            raise _err(path, 'ARRAY 需要 lenPrefix')
        elem = field_cfg.get('elem')
        if elem is None and 'fields' in field_cfg:
            elem = {'type': 'STRUCT', 'fields': field_cfg['fields']}
        if elem is None:
            raise ValueError('ARRAY 需要 elem 或 fields')
        
        cur = offset
        items: List[Any] = []
        
        if count_by_field:
            # 使用countByField进行动态分类计数
            field_name = count_by_field.get('field')
            counters = count_by_field.get('counters', [])
            
            if not field_name or not counters:
                raise ValueError('countByField 需要 field 和 counters')
            
            # 读取各个计数值
            count_values = {}
            total_count = 0
            for counter in counters:
                counter_name = counter.get('name')
                counter_type = counter.get('type', 'BYTE')
                byte_size = 1 if counter_type == 'BYTE' else 2 if counter_type == 'WORD' else 4
                count_val, cur = _read_uint(buf, cur, byte_size)
                count_values[counter_name] = count_val
                total_count += count_val
            
            # 解析数组元素
            for i in range(total_count):
                val, cur = decode_field(buf, cur, elem, path + [f'[{i}]'])
                items.append(val)
        else:
            # 使用原有的总数计数
            count, cur = _read_len_by_prefix(str(len_prefix), buf, offset)
            for i in range(count):
                val, cur = decode_field(buf, cur, elem, path + [f'[{i}]'])
                items.append(val)
        
        return items, cur
    if t == DataType.MAP.value:
        key_len = int(field_cfg.get('keyFixedLen', 0))
        val_len_prefix = field_cfg.get('valueLenPrefix')
        entries = field_cfg.get('entries', [])
        count_prefix = field_cfg.get('countPrefix')  # 新增：数量字段前缀
        count_len = int(field_cfg.get('countLen', 0))  # 新增：数量字段长度
        
        if key_len <= 0 or not val_len_prefix:
            raise ValueError('MAP 需要 keyFixedLen 与 valueLenPrefix')
        
        cur = offset
        entry_count = len(entries)  # 默认使用配置的条目数量
        
        # 如果配置了数量字段且长度大于0，先读取数量
        if count_len > 0:
            # 根据countLen隐式确定前缀类型
            if count_len == 1:
                entry_count, cur = _read_len_by_prefix("BYTE", buf, cur)
            elif count_len == 2:
                entry_count, cur = _read_len_by_prefix("WORD", buf, cur)
            elif count_len == 4:
                entry_count, cur = _read_len_by_prefix("DWORD", buf, cur)
            else:
                raise ValueError(f"不支持的countLen值: {count_len}")
        else:
            # 当countLen=0时，需要动态计算条目数量
            # 通过遍历缓冲区直到结束来确定条目数量
            temp_cur = cur
            entry_count = 0
            while temp_cur < len(buf):
                try:
                    # 尝试读取key
                    _, temp_cur = _read_uint(buf, temp_cur, key_len)
                    # 尝试读取value长度
                    ln, temp_cur2 = _read_len_by_prefix(str(val_len_prefix), buf, temp_cur)
                    temp_cur = temp_cur2 + ln
                    if temp_cur > len(buf):
                        break
                    entry_count += 1
                except:
                    break
        
        result: Dict[str, Any] = {}
        # 根据key长度确定十六进制格式的位数
        hex_width = key_len * 2  # 每个字节2个十六进制字符
        
        for i in range(entry_count):
            # 检查是否有足够的数据读取key
            if cur + key_len > len(buf):
                # 数据不完整，停止解析
                break
            key_val, cur = _read_uint(buf, cur, key_len)
            
            # 检查是否有足够的数据读取value长度
            if cur >= len(buf):
                # 数据不完整，停止解析
                break
            ln, cur2 = _read_len_by_prefix(str(val_len_prefix), buf, cur)
            
            # 检查是否有足够的数据读取value
            v_end = cur2 + ln
            if v_end > len(buf):
                # 数据不完整，停止解析
                break
            slice_bytes = buf[cur2:v_end]
            # 解码 value 按照配置
            # 查找对应的条目配置
            entry_cfg = None
            for ent in entries:
                try:
                    ent_key = int(ent.get('key', 0), 16) if isinstance(ent.get('key'), str) and ent.get('key').startswith('0x') else int(ent.get('key', 0))
                    if ent_key == key_val:
                        entry_cfg = ent
                        break
                except:
                    continue
            
            if entry_cfg:
                # 根据配置的类型进行解码
                entry_type = entry_cfg.get('type', '').upper()
                
                # 对于直接作为MAP值的长度类型字段，需要特殊处理
                # 这些类型的长度前缀在编码时被抑制了，解码器需要从MAP的valueLenPrefix中获取长度信息
                if entry_type in ['STRING', 'BYTES', 'ARRAY']:
                    # 创建临时配置，去掉lenPrefix，让解码器直接使用slice_bytes
                    temp_cfg = dict(entry_cfg)
                    if entry_type == 'STRING':
                        # STRING类型：去掉lenPrefix，使用remainder模式
                        temp_cfg.pop('lenPrefix', None)
                        temp_cfg['remainder'] = True
                    elif entry_type == 'BYTES':
                        # BYTES类型：去掉lenPrefix，使用remainder模式
                        temp_cfg.pop('lenPrefix', None)
                        temp_cfg['remainder'] = True
                    elif entry_type == 'ARRAY':
                        # ARRAY类型：去掉lenPrefix，直接解码数组内容
                        temp_cfg.pop('lenPrefix', None)
                        # 需要从slice_bytes中推断数组元素数量
                        elem = temp_cfg.get('elem')
                        if elem and elem.get('type') == 'BYTE':
                            # 对于BYTE类型的数组，每个元素1字节
                            array_items = list(slice_bytes)
                            temp_cfg['items'] = array_items
                            # 直接返回数组内容，不需要调用decode_field
                            result[f"0x{key_val:0{hex_width}x}"] = array_items
                            cur = v_end
                            continue
                        else:
                            # 其他类型需要更复杂的处理，暂时跳过
                            result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                            cur = v_end
                            continue
                    
                    # 使用临时配置解码
                    try:
                        val, _ = decode_field(slice_bytes, 0, temp_cfg, path + [f'entry_{key_val}'])
                        result[f"0x{key_val:0{hex_width}x}"] = val
                    except:
                        # 如果解码失败，返回十六进制字符串
                        result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                elif entry_type == 'BITFIELD':
                    # BITFIELD类型解码
                    size = int(entry_cfg.get('size', 32))
                    if size == 8:
                        val = slice_bytes[0] if slice_bytes else 0
                    elif size == 16:
                        val = int.from_bytes(slice_bytes[:2], 'big') if len(slice_bytes) >= 2 else 0
                    elif size == 32:
                        val = int.from_bytes(slice_bytes[:4], 'big') if len(slice_bytes) >= 4 else 0
                    elif size == 64:
                        val = int.from_bytes(slice_bytes[:8], 'big') if len(slice_bytes) >= 8 else 0
                    else:
                        val = int.from_bytes(slice_bytes, 'big')
                    
                    # 简化BITFIELD解析，输出简单的bit格式
                    bits = entry_cfg.get('bits', [])
                    if bits:
                        bitfield_result = {}
                        for bit_def in bits:
                            bit_idx = int(bit_def.get('bitIndex', 0))
                            bit_length = int(bit_def.get('bitLength', 1))
                            max_idx = size - 1
                            
                            if 0 <= bit_idx <= max_idx and bit_idx + bit_length - 1 <= max_idx:
                                # 提取连续bit的值（大端序）
                                mask = (1 << bit_length) - 1
                                bit_value = (val >> bit_idx) & mask
                                
                                # 生成简单的字段名
                                if bit_length == 1:
                                    field_name = f'bit_{bit_idx}'
                                else:
                                    field_name = f'bit_{bit_idx}_{bit_idx + bit_length - 1}'
                                
                                bitfield_result[field_name] = bit_value
                        result[f"0x{key_val:0{hex_width}x}"] = bitfield_result
                    else:
                        result[f"0x{key_val:0{hex_width}x}"] = val
                elif entry_type == 'STRUCT':
                    # STRUCT类型解码
                    fields = entry_cfg.get('fields', [])
                    if fields:
                        # 递归解析STRUCT字段，先按order排序
                        fields_sorted = sorted(fields, key=lambda f: int(f.get('order', 0)))
                        struct_result = {}
                        temp_offset = 0
                        # 条件字段上下文
                        context = {}
                        for field in fields_sorted:
                            field_name = field.get('name', f'field_{temp_offset}')
                            try:
                                # 检查条件字段
                                if 'conditional' in field:
                                    cond = str(field['conditional'])
                                    if ' || ' in cond:
                                        conditions = cond.split(' || ')
                                        ok = False
                                        for sub_cond in conditions:
                                            if _evaluate_simple_condition(sub_cond.strip(), context):
                                                ok = True
                                                break
                                        if not ok:
                                            continue
                                    elif ' && ' in cond:
                                        conditions = cond.split(' && ')
                                        ok = True
                                        for sub_cond in conditions:
                                            if not _evaluate_simple_condition(sub_cond.strip(), context):
                                                ok = False
                                                break
                                        if not ok:
                                            continue
                                    else:
                                        if not _evaluate_simple_condition(cond, context):
                                            continue
                                
                                field_result, temp_offset = decode_field(slice_bytes, temp_offset, field, path + [f'entry_{key_val}', field_name])
                                struct_result[field_name] = field_result
                                
                                # 更新上下文（用于条件字段）
                                if field.get('type') == 'BYTE':
                                    context[field_name] = field_result
                            except Exception as e:
                                # 如果解析失败，记录错误信息并跳过该字段
                                struct_result[field_name] = f"<解析失败: {str(e)}>"
                                continue
                        result[f"0x{key_val:0{hex_width}x}"] = struct_result
                    else:
                        result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                elif entry_type == 'STRING':
                    # STRING类型解码
                    charset = entry_cfg.get('charset', 'gbk')
                    try:
                        decoded_str = slice_bytes.decode(charset).rstrip('\x00')
                        result[f"0x{key_val:0{hex_width}x}"] = decoded_str
                    except:
                        result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                elif entry_type == 'BCD':
                    # BCD类型解码
                    digits = int(entry_cfg.get('digits', 0))
                    if digits > 0:
                        try:
                            bcd_result, _ = _decode_bcd_bytes(slice_bytes, 0, digits)
                            result[f"0x{key_val:0{hex_width}x}"] = bcd_result
                        except:
                            result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                    else:
                        result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                elif entry_type in ['BYTE', 'WORD', 'DWORD']:
                    # 数值类型解码
                    size_map = {'BYTE': 1, 'WORD': 2, 'DWORD': 4}
                    size = size_map.get(entry_type, 1)
                    if len(slice_bytes) >= size:
                        val = int.from_bytes(slice_bytes[:size], 'big')
                        result[f"0x{key_val:0{hex_width}x}"] = val
                    else:
                        result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
                else:
                    # 其他类型按十六进制字符串返回
                    result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
            else:
                # 没有找到配置，按十六进制字符串返回
                result[f"0x{key_val:0{hex_width}x}"] = slice_bytes.hex()
            cur = v_end
        return result, cur
    raise ValueError(f'未支持的类型: {t}')


